import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Lesson8 {

    /**
     *  完成计算异常
     *  现在我们来看一下异步操作如何显式地返回异常，用来指示计算失败。
     *  操作处理一个字符串，把它转换成大写，我们模拟延迟一秒。
     *
     * 我们使用thenApplyAsync(Function, Executor)方法，
     * 第一个参数传入大写函数， executor是一个delayed executor,在执行前会延迟一秒。
     *
     * 让我们看一下细节。
     *
     * 首先我们创建了一个CompletableFuture, 完成后返回一个字符串message,接着我们调用thenApplyAsync方法，它返回一个CompletableFuture。
     * 这个方法在第一个函数完成后，异步地应用转大写字母函数。
     *
     * 这个例子还演示了如何通过delayedExecutor(timeout, timeUnit)延迟执行一个异步任务。
     *
     * 我们创建了一个分离的handler阶段：exceptionHandler， 它处理异常异常，在异常情况下返回message upon cancel。
     *
     * 下一步我们显式地用异常完成第二个阶段。
     * 在阶段上调用join方法，它会执行大写转换，然后抛出CompletionException（正常的join会等待1秒，然后得到大写的字符串。
     * 不过我们的例子还没等它执行就完成了异常）， 然后它触发了handler阶段。
     *
     * */

    private static AtomicInteger atomicInteger = new AtomicInteger(1);

    private static ExecutorService executorService = new ThreadPoolExecutor(10, 10, 1, TimeUnit.HOURS, new ArrayBlockingQueue(10), r -> {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        thread.setName("custom-executor-" + atomicInteger.incrementAndGet());
        return thread;
    });

    public static void main(String[] args) {
        CompletableFuture completableFuture =  CompletableFuture
                .completedFuture("message")
                .thenApplyAsync(s -> {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return s.toUpperCase();
                }, executorService);

        CompletableFuture exceptionHandler = completableFuture.handle((s, th) -> {return (th != null) ? "message upon cancel" : "";});

        completableFuture.completeExceptionally(new RuntimeException("complete exceptionally"));

        System.out.println(completableFuture.isCompletedExceptionally());

        completableFuture.join();

        System.out.println(completableFuture.isCompletedExceptionally());

        exceptionHandler.join();
    }
}
